package com.dodoke.framework.security.wechat.provider;

import com.dodoke.framework.security.wechat.token.WechatAuthenticationToken;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.Assert;

/**
 * 微信认证策略入口
 */
public class WechatAuthenticationProvider implements AuthenticationProvider {

    // 上下文中的 userDetailsService
    private UserDetailsService userDetailsService;
    private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();


    @Override
    public Authentication authenticate(Authentication authentication) {
        Assert.isInstanceOf(WechatAuthenticationToken.class, authentication,
                messages.getMessage(
                        "SmsAuthenticationProvider.onlySupports",
                        "Only SmsAuthenticationToken is supported"));

        WechatAuthenticationToken authenticationToken = (WechatAuthenticationToken) authentication;
        //将验证信息保存在SecurityContext以供UserDetailsService进行验证
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authenticationToken);
        String openId = (String) authenticationToken.getPrincipal();
        if (openId == null) {
            throw new InternalAuthenticationServiceException("can't obtain user info ");
        }
        openId = openId.trim();

        //进行验证以及获取用户信息
        UserDetails user = userDetailsService.loadUserByUsername(openId);
        if (user == null) {
            throw new InternalAuthenticationServiceException("can't obtain user info ");
        }
        return new WechatAuthenticationToken(user, user.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        // 判断 authentication 是不是 SmsCodeAuthenticationToken 的子类或子接口
        return (WechatAuthenticationToken.class.isAssignableFrom(authentication));
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }
}
